#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/* 为什么要用二级指针？
 * 如果我们要在一个函数内改变一个指针的值，我们就需要将形参定义为二级指针 
 * 函数的形参无法直接改变一级指针实参的地址，因为函数中只传递了指针的副本，如下面的函数不能直接用arr的地址当参数，而需要用二级指针
 * 但是可以改变实参的值，如swap函数
 */
int add_elem(int **p, int *size, int elem);
int find_elem(const int *p, const int *size, int elem);
int del_elem(int **p, int *size, int elem);
void traval(const int *p, const int *size);

int main(void)
{
    int *arr = NULL; // 数组本身
    int size = 0; // 数组的长度

    int i;

    for (i = 0; i < 10; i++) { // 添加10个元素
        add_elem(&arr, &size, i + 1);
        printf("add(%d),size = %d\n", i + 1, size);
    }

    traval(arr, &size); // 遍历打印

    if (del_elem(&arr, &size, 4) == -1) 
        printf("删除%d失败\n", 4);
    else
        printf("删除%d成功\n", 4);

    traval(arr, &size); // 遍历打印

    printf("元素%d是第%d个元素\n", 6, find_elem(arr, &size, 6) + 1);

    free(arr);
    arr = NULL;
    return 0;
}

/* 向动态数组添加元素 elem */
int add_elem(int **p, int *size, int elem)
{
    int *ptr = NULL; // 定义一个临时变量，防止开辟失败使得*p变为NULL
    ptr = (int *)realloc(*p, (*size + 1) * sizeof(int));

    if (ptr == NULL) // 如果失败，返回 NULL，并且原来的内存块仍然保持不变（并没有释放）
        return -1; // 开辟失败返回状态值-1

    *p = ptr; // 开辟成功则改变指向
    (*p)[*size] = elem; // 注意此处运算符的优先级，*p要加括号
    (*size)++;

    return 0;
}

/* 删除第一个元素值为 elem 的元素 */
int del_elem(int **p, int *size, int elem)
{
    int ind = find_elem(*p, size, elem);
    int *ptr = NULL;

    if (ind == -1)
        return -1; // 未找到元素，删除失败

    memcpy(*p + ind, *p + ind + 1, sizeof(int) * (*size - ind - 1)); // src > dest，有内存区间覆盖也不会产生问题

    ptr = realloc(*p, (*size - 1) * sizeof(int));
    if (ptr == NULL)
        return -1;

    *p = ptr;
    (*size)--; // 删除成功，尺寸-1

    return 0;
}

/* 遍历输出所有元素 */
void traval(const int *p, const int *size)
{
    int i;
    for (i = 0; i < *size; i++)
        printf("%d ", p[i]);
    printf("\n");
}

/* 查找元素值为 elem 的元素的下标 */
int find_elem(const int *p, const int *size, int elem)
{
    int ind;

    for (ind = 0; ind < *size; ind++) {
        if (p[ind] == elem)
            return ind;
    }

    return -1; // 未找到元素
}


